﻿using FolderSync.Sync.Dto;
using FolderSync.Sync.Sto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FolderSync.Sync
{
    /// <summary>
    /// 目录同步器
    /// </summary>
    public class FolderSyncer
    {
        // 私有变量
        private readonly FrmMain _frmMain;

        /// <summary>
        /// 目录同步器
        /// </summary>
        /// <param name="frmMain"></param>
        public FolderSyncer(FrmMain frmMain)
        {
            _frmMain = frmMain;
        }

        /// <summary>
        /// 同步
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public List<SyncOutput> Sync(SyncInput input)
        {
            if (input.SyncFiles is null) return new List<SyncOutput>();
            List<SyncOutput> outputs = new List<SyncOutput>();
            // 获取所有的目录
            _frmMain.SetStatus($"正在同步 {input.SourceFolder} ...");
            var folders = egg.IO.GetFolders(input.SourceFolder);
            // 创建目录
            for (int i = 0; i < folders.Length; i++)
            {
                var folder = folders[i];
                var path = folder.Substring(input.SourceRoot.Length);
                var targetPath = input.TargetRoot + path;
                egg.IO.CreateFolder(targetPath);
                // 处理子目录
                var syncOutputs = Sync(new SyncInput()
                {
                    SourceFolder = folder,
                    TargetFolder = targetPath,
                    SourceRoot = input.SourceRoot,
                    TargetRoot = input.TargetRoot,
                    SyncFiles = input.SyncFiles,
                });
                if (syncOutputs.Any()) outputs.AddRange(syncOutputs);
            }
            // 获取所有文件
            var files = egg.IO.GetFiles(input.SourceFolder);
            for (int i = 0; i < files.Length; i++)
            {
                var file = files[i];
                var path = file.Substring(input.SourceRoot.Length);
                var targetPath = input.TargetRoot + path;
                try
                {
                    var info = new FileInfo(file);
                    var lastWriteTime = egg.Time.Parse(info.LastWriteTime).ToUnixTimeSeconds();
                    var syncFile = input.SyncFiles.Where(d => d.Path == path).FirstOrDefault();
                    bool needSync = false;
                    if (syncFile is null)
                    {
                        // 判断，如果存在，则检测Md5
                        if (egg.IO.CheckFileExists(targetPath))
                        {
                            _frmMain.SetStatus($"正在对比文件MD5 {file} ...");
                            var sourceMd5 = egg.IO.GetMD5(file);
                            var targetMd5 = egg.IO.GetMD5(targetPath);
                            if (sourceMd5 != targetPath)
                            {
                                needSync = true;
                            }
                            else
                            {
                                // 添加同步结果
                                outputs.Add(new SyncOutput()
                                {
                                    IsSync = true,
                                    Path = path,
                                    LastWriteTime = lastWriteTime,
                                });
                            }
                        }
                        else needSync = true;
                    }
                    else
                    {
                        if (syncFile.LastWriteTime != lastWriteTime)
                            needSync = true;
                    }
                    if (needSync)
                    {
                        // 复制文件
                        _frmMain.SetStatus($"正在复制文件 {file} ...");
                        byte[] buffer = new byte[1024 * 64];
                        using (var sourcFile = egg.IO.OpenFile(file, FileMode.Open, FileAccess.Read))
                        {
                            using (var targetFile = egg.IO.OpenFile(targetPath, FileMode.Create, FileAccess.Write))
                            {
                                int len = 0;
                                int tick = Environment.TickCount;
                                long speed = 0;
                                double lastSpeed = 0;
                                double fileLength = (double)sourcFile.Length;
                                double mb = 1024.0 * 1024.0;
                                do
                                {
                                    len = sourcFile.Read(buffer, 0, buffer.Length);
                                    long pos = sourcFile.Position;
                                    if (len > 0)
                                    {
                                        targetFile.Write(buffer, 0, len);
                                        // 计算速度
                                        speed += len;
                                        if (Environment.TickCount - tick > 1000)
                                        {
                                            tick = Environment.TickCount;
                                            lastSpeed = Math.Round(speed / mb, 2);
                                            speed = 0;
                                            double percent = Math.Round(pos / fileLength * 100, 2);
                                            _frmMain.SetStatus($"正在复制文件 {file} {percent}% {lastSpeed}MB/s ...");
                                        }
                                    }
                                } while (len > 0);
                            }
                        }
                        //File.Copy(file, targetPath, true);
                        // 添加同步结果
                        outputs.Add(new SyncOutput()
                        {
                            IsSync = true,
                            Path = path,
                            LastWriteTime = lastWriteTime,
                        });
                    }
                }
                catch
                {
                    // 添加同步结果
                    outputs.Add(new SyncOutput()
                    {
                        IsSync = false,
                        Path = path,
                    });
                }

            }
            return outputs;
        }
    }
}
